#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <fstream>
#include <string>
#include <stdio.h>
#include <cstring>

using namespace std;

#define BUFFERSIZE 32

// 命令行参数
// argc：表示命令行参数个数
// argv[]：表示命令行参数的字段
int main(int argc, char *argv[])
{
#if 0
    // 了解命令行参数
    cout << "argc:" << argc << endl;
    for (int idx = 0; idx < argc; idx++)
    {
        printf("argv[%d] = %s\n", idx, argv[idx]);
    }
#endif

#if 1
    // 检查命令行参数的个数
    if (argc != 3)
    {
        // 参数数量有误
        cout << "argument cnt error." << endl;
    }

    const char *srcFile = argv[1];
    const char *dstFile = argv[2];

    // 打开源文件
    int srcFd = open(srcFile, O_RDONLY);
    if (srcFd == -1)
    {
        perror("src file open error");
        exit(-1);
    }

    // 权限（./myCp可以拷贝普通文件也可以拷贝二进制文件，唯一的问题是得不到文件的权限）
    // 要想在目标文件把权限拿到，就需要知道原文件的权限是什么样子的
    // access函数只能够判断文件是否包含某种权限，但是并不能够深入用户组内，必须开root权限执行代码 
    // ??? todo...
    int permission = 0;
    access(srcFile, R_OK) == 0 ? (permission |= R_OK) : permission;
    access(srcFile, W_OK) == 0 ? (permission |= W_OK) : permission;
    access(srcFile, X_OK) == 0 ? (permission |= X_OK) : permission;

    // 用户组的问题
    
    // 打开目标文件
    int dstFd = open(dstFile, O_WRONLY | O_CREAT, 0644); // todo...
    if (dstFd == -1)
    {
        perror("dst file open error");
        exit(-1);
    }

    char buffer[BUFFERSIZE + 1] = { 0 }; // 留一个结束符
    int readBytes = 0;
    // 每次读BUFFERSIZE个字节
    while (1)
    {
        readBytes = read(srcFd, buffer, BUFFERSIZE);
        // 如果读到的字节比要求的字节少，说明读完了
        if (readBytes < BUFFERSIZE)
        {
            write(dstFd, buffer, readBytes);
            break;
        }
        else
        {
            write(dstFd, buffer, readBytes);
        }
        // 清除脏数据
        memset(buffer, 0, sizeof(buffer));
    }

    // 关闭文件
    close(srcFd);
    close(dstFd);
#endif

/* MD5（Message Digest Algorithm 5）是一种广泛使用的哈希函数。
   它会将输入数据映射为一个固定长度的128位哈希值（通常以32位十六进制数字表示），主要用于校验文件或消息的完整性。
   md5sum 是一个用于生成和验证文件的 MD5 哈希值的工具（md5sum filename）
*/

    return 0;
}